﻿// FindLargeFolderCPP.cpp: 定义应用程序的入口点。
//

#include "FindLargeFolderCPP.h"
#include "FolderSize.h"

using namespace std;
namespace fs = std::filesystem;


uintmax_t calcDirFilesSize(const string& dir) {
	uintmax_t size = 0;
	try
	{
		WIN32_FIND_DATA find_data;
		HANDLE h_find;

		h_find = FindFirstFile((dir+"\\*").c_str(), &find_data);
		if (h_find == INVALID_HANDLE_VALUE) {
			std::cout << "无法打开文件夹: " << dir << std::endl;
			return 0;
		}

		do {
			if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
				
			}
			else {
				size += (static_cast<unsigned long long>(find_data.nFileSizeHigh) << 32) | static_cast<unsigned long long>(find_data.nFileSizeLow);
			}
		} while (FindNextFile(h_find, &find_data));

		FindClose(h_find);
	
	}
	catch (const fs::filesystem_error& e) {
		std::cerr << e.what() << std::endl;
	}
	return size;
}



uintmax_t calcDirSize(FolderSize* folderSize) {
	if ((*folderSize).sizeAvailable) {
		return (*folderSize).size;
	}
	uintmax_t size = 0;
	try
	{
		for (FolderSize* subFolder : *((*folderSize).subFolders)) {
			if ((*subFolder).sizeAvailable)
			{
				size += (*subFolder).size;
			}
			else
			{
				size += calcDirSize(subFolder);
			}
		}
		size += calcDirFilesSize((*folderSize).path);
		(*folderSize).size = size;
		(*folderSize).sizeAvailable = true;

	}
	catch (const fs::filesystem_error& e) {
		std::cerr << e.what() << std::endl;
	}
	return size;
}

bool compareDepth(FolderSize* fs1, FolderSize* fs2) {
	return (*fs1).depth > (*fs2).depth;
}

bool compareSize(FolderSize* fs1, FolderSize* fs2) {
	return (*fs1).size > (*fs2).size;
}

string presentSize(uintmax_t size)
{
	if (size > 1024 * 1024 * 1024)
	{
		return to_string((double)size / (double)(1024 * 1024 * 1024)) + "GB";
	}
	else if (size > 1024 * 1024)
	{
		return to_string((double)size / (double)(1024 * 1024)) + "MB";
	}
	else if (size > 1024)
	{
		return to_string((double)size / (double)(1024 )) + "KB";
	}
	else
	{
		return to_string(size) + "bytes";
	}
}

bool IsDirectory(const std::string& path) {
	struct _finddata_t fileData;
	intptr_t handle = _findfirst((path + "\\*").c_str(), &fileData);
	if (handle != -1) {
		_findclose(handle);
		return true;
	}
	return false;
}

int main(int argc, char* argv[])
{
	//calcDirFilesSize("C:");
	std::string path = "C:\\Windows";
	for (int i = 0; i < argc; ++i) {
		std::cout << "Argument " << i << ": " << argv[i] << std::endl;
	}

	int top = 30;
	for (int i = 0;i < argc;i++) {
		std::string arg = argv[i];
		if (arg == "-D" && i + 1 < argc) {
			path = argv[i + 1];
		}
		else if (arg == "-T" && i + 1 < argc) {
			top = std::stoi(argv[i + 1]);
		}
	}
	try {
		if (IsDirectory(path)) {
			vector<FolderSize*> allDirs = vector<FolderSize*>();
			vector<FolderSize*> currentLevel = vector<FolderSize*>();
			FolderSize* root =new FolderSize(path, 0, 0, false);
			currentLevel.push_back(root);
			allDirs.push_back(root);
			int found = 0;
			int currentDepth = 0;
			while (currentLevel.size() > 0) {
				currentDepth += 1;
				vector<FolderSize*> nextLevel = vector<FolderSize*>();
				for (FolderSize* folderSize : currentLevel) {
					string currentPath = (*folderSize).path;

					WIN32_FIND_DATA find_data;
					HANDLE h_find;

					h_find = FindFirstFile((currentPath + "\\*").c_str(), &find_data);
					if (h_find == INVALID_HANDLE_VALUE) {
						std::cout << "无法打开文件夹: " << currentPath << std::endl;
						continue;
					}

					do {
						if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && strcmp(find_data.cFileName,".")!=0 && strcmp(find_data.cFileName, "..") != 0) {
							if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == false) {
								string subPath = currentPath +"\\"+ find_data.cFileName;
								found += 1;
								FolderSize* subFolderSize = new FolderSize(subPath, 0, currentDepth, false);
								nextLevel.push_back(subFolderSize);
								allDirs.push_back(subFolderSize);
								(*(*folderSize).subFolders).push_back(subFolderSize);
								std::cout << "找到子文件夹个数: " + to_string(found) << std::endl;
							}
						}

					} while (FindNextFile(h_find, &find_data));

					FindClose(h_find);
				}
				currentLevel.swap(nextLevel);
			}

			sort(allDirs.begin(), allDirs.end(), compareDepth);

			int calced = 0;
			for (FolderSize* folderSize : allDirs) {
				calcDirSize(folderSize);
				calced += 1;
				std::cout << "当前进度:" + to_string(calced) + "/" + to_string(allDirs.size()) << std::endl;
			}

			sort(allDirs.begin(), allDirs.end(), compareSize);

			for (int i = 0;i < 30;i++) {
				if (i < allDirs.size()) {
					FolderSize* folderSize = allDirs[i];
					std::cout << (*folderSize).path + " " + presentSize((*folderSize).size) << std::endl;
				}
			}

			for (FolderSize* folderSize : allDirs) {
				delete (*folderSize).subFolders;
				delete folderSize;
			}

		}
		else {
			std::cerr << "Path does not exist or is not a directory." << std::endl;
		}
	}
	catch (const fs::filesystem_error& e) {
		std::cerr << e.what() << std::endl;
	}

	return 0;
}


